/*
 * Copyright 2014, General Dynamics C4 Systems
 *
 * SPDX-License-Identifier: GPL-2.0-only
 */

#include <linker.h>
#include <machine/io.h>
#include <plat/machine/hardware.h>
#include <plat/machine/pic.h>

/* PIC (i8259) base registers */
#define PIC1_BASE 0x20  /*Z 主8259命令端口，0x21为数据端口 */
#define PIC2_BASE 0xa0  /*Z 从8259命令端口，0xa1为数据端口 */
/*Z 重新映射8259中断到中断向量表 */
/* Program PIC (i8259) to remap IRQs 0-15 to interrupt vectors starting at 'interrupt' */
BOOT_CODE void pic_remap_irqs(interrupt_t interrupt)
{
    out8(PIC1_BASE, 0x11);              /*Z 初始化并等待3个数据 */
    out8(PIC2_BASE, 0x11);
    out8(PIC1_BASE + 1, interrupt);     /*Z 数据1：中断向量表中的偏移量。在IDT中的向量号变成32+x  */
    out8(PIC2_BASE + 1, interrupt + 8);
    out8(PIC1_BASE + 1, 0x04);          /*Z 数据2：告诉主芯片，IRQ2是从芯片 */
    out8(PIC2_BASE + 1, 0x02);
    out8(PIC1_BASE + 1, 0x01);          /*Z 数据3：8086/88 (MCS-80/85) 模式 */
    out8(PIC2_BASE + 1, 0x01);
    out8(PIC1_BASE + 1, 0x0);           /*Z 清零数据端口 */
    out8(PIC2_BASE + 1, 0x0);
}
/*Z 禁用8258中断控制器 */
BOOT_CODE void pic_disable(void)
{
    /* We assume that pic_remap_irqs has already been called and
     * just mask all the irqs */
    out8(PIC1_BASE + 1, 0xff);
    out8(PIC2_BASE + 1, 0xff);
}
/*Z 设置0～16号PIC中断掩码，mask: 1-禁用，0-启用 */
void pic_mask_irq(bool_t mask, irq_t irq)
{
    uint8_t  bit_mask;
    uint16_t pic_port;

    assert(irq >= irq_isa_min);
    assert(irq <= irq_isa_max);

    if (irq < 8) {/*Z 主8259A */
        bit_mask = BIT(irq);
        pic_port = PIC1_BASE + 1;
    } else {/*Z 从8259A */
        bit_mask = BIT(irq - 8);
        pic_port = PIC2_BASE + 1;
    }

    if (mask) {
        /* Disables the interrupt */
        out8(pic_port, (in8(pic_port) | bit_mask));
    } else {
        /* Enables the interrupt */
        out8(pic_port, (in8(pic_port) & ~bit_mask));
    }
}
/*Z 是否有中断pending */
bool_t pic_is_irq_pending(void)
{
    /* Interrupt Request Register (IRR) - holds pending IRQs */
    uint8_t irr;

    /* Send to PIC1's OCW3, in order to read IRR from next inb instruction */
    out8(PIC1_BASE, 0x0a);

    /* Read IRR */
    irr = in8(PIC1_BASE);

    /* Since slave PIC is connected to IRQ2 of master PIC,
     * there is no need to check IRR of slave PIC.
     */
    return irr != 0;
}
/*Z 读取主、从PIC正在服务的IRQ号。低字节主、高字节从 */
static uint16_t pic_get_isr(void)
{
    out8(PIC1_BASE, 0x0b);
    out8(PIC2_BASE, 0x0b);
    return (((uint16_t)in8(PIC2_BASE)) << 8) | in8(PIC1_BASE);
}
/*Z 向PIC发出当前中断服务完成的信号 */
void pic_ack_active_irq(void)
{
    irq_t irq = getActiveIRQ();/*Z 从全局变量获取或轮询IRQ */
    if (irq >= irq_isa_min + 8) {/*Z 从PIC的 */
        /* ack slave PIC, unless we got a spurious irq 15
         * It is spurious if the bit is not set in the ISR
         * Even if it was spurious we will still need to
         * acknowledge the master PIC *//*Z 不是可能的假中断IRQ15，或IRQ15确实正在服务中 */
        if (irq != irq_isa_min + 15 || (pic_get_isr() & BIT(15))) {
            out8(PIC2_BASE, 0x20);/*Z 则发出中断服务完成信号 */
        }
    }
    /* ack master PIC, unless we got a spurious IRQ 7
     * It is spurious if the bit is not set in the ISR */
    if (irq != irq_isa_min + 7 || (pic_get_isr() & BIT(7))) {
        out8(PIC1_BASE, 0x20);
    }
}
